/**
 * 
 */
package com.zcsy.commons.unique;

import java.util.Properties;
import java.util.Random;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * <p>用于生成唯一数字，注意如果需要在不同程序中唯一，需要配置localUniqueId为其它值</p>
 * <b>最后修改时间：</b><br>
 * &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2012-7-13上午11:21:29
 * 
 * @author zhengwei.bu
 * @version 1.0
 */
public class UniqueNumberUtils {
	private static final Lock LOCK = new ReentrantLock();
	private static final String localUniqueId = "1";//用于标识本程序唯一ID，其它程序使用本类要更改ID，范围1~9
	
	private static String lastTimeMillis=null;//存放上一次的毫秒数
	private static long count=0L;//存放在一毫秒内的累加数
	
	//获取本程序机器代码
	public static String getLocalNum() {
		return localUniqueId;
	}
	
	/**
	 * <p>获取16长度的唯一数字，在2286-11-21 01:46:39之前是唯一的</p>
	 * <b>最后修改时间：</b><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2012-7-13下午03:24:39
	 * @return 16长度的唯一数字
	 */
	public static String get16UniqueNumber(){
		return getUniqueNumber(16);
	}
	
	/**
	 * <p>获取18长度的唯一数字，在33658-09-27 09:46:39之前是唯一的</p>
	 * <b>最后修改时间：</b><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2012-7-13下午03:24:39
	 * @return 18长度的唯一数字
	 */
	public static String get18UniqueNumber(){
		return getUniqueNumber(18);
	}
	
	/**
	 * <p>获取指定长度(最短16位)的唯一数字
	 * <br>长度为16位时在2286-11-21 01:46:39之前是唯一的
	 * <br>长度为18位时在33658-09-27 09:46:39之前是唯一的
	 * <br>长度越长有效期越长
	 * </p>
	 * <b>最后修改时间：</b><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2012-7-13下午03:56:09
	 * @param uniqueNumberLength 指定长度
	 * @return 指定长度的唯一数字
	 */
	public static String getUniqueNumber(int uniqueNumberLength) {
		LOCK.lock();
		try {
			int timeMillisLength=uniqueNumberLength-3;
			if(timeMillisLength<0) timeMillisLength=13;
			String currentTimeMillis=String.format("%1$0"+timeMillisLength+"d", System.currentTimeMillis());
			currentTimeMillis=currentTimeMillis.substring(currentTimeMillis.length()-timeMillisLength);
			if(lastTimeMillis==null){
				lastTimeMillis=currentTimeMillis;
			}			
			if(!currentTimeMillis.equals(lastTimeMillis)){
				count=0L;
			}else if(count>99L){	
				try {
					Thread.currentThread().sleep(1);
				} catch (java.lang.InterruptedException e) {
				}
				count=0L;
			} 
			lastTimeMillis=currentTimeMillis;
			return localUniqueId+currentTimeMillis+String.format("%1$02d",count++);
		} finally {
			LOCK.unlock();
		}
	}
	
	public static String getUniqueNumberNew(int uniqueNumberLength) {
		LOCK.lock();
		try {
			int timeMillisLength=uniqueNumberLength-1;
			if(timeMillisLength<0) timeMillisLength=13;
			String currentTimeMillis=String.format("%1$0"+timeMillisLength+"d", System.currentTimeMillis());
			currentTimeMillis=currentTimeMillis.substring(currentTimeMillis.length()-timeMillisLength);
			if(lastTimeMillis==null){
				lastTimeMillis=currentTimeMillis;
			}			
			if(!currentTimeMillis.equals(lastTimeMillis)){
				count=0L;
			}else if(count>99L){	
				try {
					Thread.currentThread().sleep(1);
				} catch (java.lang.InterruptedException e) {
				}
				count=0L;
			} 
			lastTimeMillis=currentTimeMillis;
			return localUniqueId+currentTimeMillis;
		} finally {
			LOCK.unlock();
		}
	}
	
	public static void main(String[] args) throws InterruptedException {
		for(int i=0;i<9999;i++){
			System.out.println(UniqueNumberUtils.get18UniqueNumber());
		}
	}
}
